#ifndef _GC_COMMON_UTIL_H_
#define _GC_COMMON_UTIL_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <json/json.h>

#include "config.h"
#include "list.h"


char * gc_get_hostaddr(char * addr, socklen_t size) {
	struct hostent * h = gethostent();
	memset(addr, 0, size);
	if(h != NULL) {
		if(inet_ntop(h->h_addrtype, h->h_addr_list[0], addr, size) != NULL) {
			return addr;
		}
		fprintf(stderr, "%s:%d inet_ntop return %d\n", __FILE__, __LINE__, errno);
	}
	return addr;
}	

inline static char * gc_charmask(char * str, size_t len, const char * mask) {
	memset(str, 0, len);	
	while(*mask) {
		str[(unsigned char) *mask ++] = 1;
	}
	return str;
} 

char *gc_trim(char * str) {
	char trim_mask[256] = {0};
	int from = 0, len = strlen(str), to = len - 1;

	if(len > 0) { 
		gc_charmask((char *)trim_mask, sizeof(trim_mask), " \t\r\n\v");

		while(trim_mask[(unsigned char)str[from]]) ++ from;

		while(to > from && trim_mask[(unsigned char)str[to]]) -- to;

		len = to - from + 1;
		int i;
		for(i = 0; i < len; i ++) {
			str[i] = str[i + from];
		}
		str[len] = '\0';
	}
	
	return str;
}

gc_list_t * gc_convert_json_object_to_list(json_object * json) {
   
	if(json == NULL || !json_object_is_type(json, json_type_array)) {
		fprintf(stderr, "%s:%d: json_object is null or is not a array\n",
				__FILE__, __LINE__);	
		return NULL;
	}

	int i = 0, len = 0;
	json_object * row = NULL, *value = NULL;

	gc_list_t * list = gc_list_create();

	int val_type = 0, ver = 0;
	const char *k = NULL, *v = NULL;

	for(i = 0, len = json_object_array_length(json); i < len; i++) {
		row = json_object_array_get_idx(json, i);		

		value = json_object_object_get(row, "k");
		k = json_object_get_string(value);

		value = json_object_object_get(row, "v");
		v = json_object_get_string(value);

		value = json_object_object_get(row, "vt");
		val_type = json_object_get_int(value);

		value = json_object_object_get(row, "ver");
		ver = json_object_get_int(value);

		gc_list_push(list, k, strlen(k), v, strlen(v), val_type, ver);
	}

	return list;
}

json_object * gc_list_data_to_json_object(gc_list_data_t * val) {
	json_object * ret = NULL;
	switch(val->type) {
		case TYPE_INT:
			ret = json_object_new_int(val->data.int_val);
			break;
		case TYPE_DOUBLE:
			ret =  json_object_new_double(val->data.dbl_val);
			break;
		case TYPE_STRING:
		case TYPE_ARRAY:
			ret = json_object_new_string(val->data.str_val);
			break;
	}

	return ret;
}

json_object * gc_convert_list_to_json_object(const gc_list_t * list) {
	json_object * json = NULL;
	if(list != NULL) {
		json = json_object_new_array();
		json_object * t = NULL;
		gc_list_data_t *next = list->head;

		while(next != NULL) {
			t = json_object_new_object();

			json_object_object_add(t, "k", json_object_new_string(next->key));
			json_object_object_add(t, "v", gc_list_data_to_json_object(next));
			json_object_object_add(t, "vt", json_object_new_int(next->type));
			json_object_object_add(t, "ver", json_object_new_int(next->ver));

			json_object_array_add(json, t);

			next = next->next;
		}
	}

	return json;
}

#endif
